package com.aruio.aop;

import com.alibaba.fastjson2.JSON;
import com.aruio.annotation.MyLog;
import com.aruio.entity.ExceptionLog;
import com.aruio.entity.OperationLog;
import com.aruio.service.ExceptionLogService;
import com.aruio.service.OperationLogService;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 操作日志处理切面类
 * @Date 2024/8/21 15:32
 * @Created by 10574
 */
@Aspect
@Component
@RequiredArgsConstructor
public class OperationLogAspect {
    private static final String VERSION = "v0.0.1";
    private final OperationLogService operationLogService;
    private final ExceptionLogService exceptionLogService;

    @Pointcut("@annotation(com.aruio.annotation.MyLog)")
    public void operationLogPointCut() {
    }

    @Pointcut("execution(* com.hyd.zcar.cms.controller..*.*(..))")
    public void exceptionLogPointCut() {
    }

    @AfterReturning(value = "operationLogPointCut()", returning = "returnValues")
    public void saveOperationLog(JoinPoint joinPoint, Object returnValues) {
        final HttpServletRequest request = getRequest();

        final OperationLog operationLog = new OperationLog();

        //保存注解信息
        final Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        final MyLog myLog = method.getAnnotation(MyLog.class);
        operationLog.setOperationModule(myLog.operationModule());
        operationLog.setOperationType(myLog.operationType());
        operationLog.setOperationDesc(myLog.operationDesc());

        // 保存其他信息
        final String param = convertMapToJSON(request.getParameterMap());
        operationLog.setOperationRequestParam(param);
        operationLog.setOperationResponseParam(JSON.toJSONString(returnValues));
        operationLog.setOperationUserId(1);
        operationLog.setOperationUserName("zhanyurui");
        operationLog.setOperationMethod(joinPoint.getTarget().getClass().getName() + "." + ((MethodSignature) joinPoint.getSignature()).getMethod().getName());
        operationLog.setOperationUri(request.getRequestURI());
        operationLog.setOperationIp(request.getRemoteHost());
        operationLog.setOperationVersion(VERSION);
        operationLogService.save(operationLog);
    }

    @AfterThrowing(pointcut = "exceptionLogPointCut()", throwing = "e")
    public void saveExceptionLog(JoinPoint joinPoint, Exception e) {
        final HttpServletRequest request = getRequest();
        final ExceptionLog exceptionLog = new ExceptionLog();
        //保存异常信息
        exceptionLog.setExceptionName(e.getClass().getName());
        exceptionLog.setExceptionMessage(e.getMessage());

        // 保存其他信息
        final String param = convertMapToJSON(request.getParameterMap());
        exceptionLog.setExceptionRequestParam(param);
        exceptionLog.setOperationUserId(1);
        exceptionLog.setOperationUserName("zhanyurui");
        exceptionLog.setOperationMethod(joinPoint.getTarget().getClass().getName() + "." + ((MethodSignature) joinPoint.getSignature()).getMethod().getName());
        exceptionLog.setOperationUri(request.getRequestURI());
        exceptionLog.setOperationIp(request.getRemoteHost());
        exceptionLog.setOperationVersion(VERSION);
        exceptionLogService.save(exceptionLog);
    }

    private static HttpServletRequest getRequest() {
        final ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Assert.notNull(requestAttributes, "requestAttributes not null");
        return requestAttributes.getRequest();
    }

    private static String convertMapToJSON(Map<String, String[]> map){
        final Map<String, String> requestParamMap = new HashMap<>();
        map.forEach((key, value) -> {
            requestParamMap.put(key, value.length > 1 ? Arrays.toString(value) : value[0]);
        });
        return JSON.toJSONString(requestParamMap);
    }
}
